<?php

namespace App\Admin\Utils;

use Illuminate\Http\UploadedFile;
use Request;

class SimpleUpload
{
    /**
     * 文件存储名的前缀
     *
     * @var string
     */
    protected $prefix = '';

    /**
     * 外部可调用的接收处理plupload传来的文件
     *
     * @param string $name 文件字段名
     * @return null|UploadedFile
     */
    public function receive($name)
    {
        $result = null;

        if ($file = Request::file($name)) {
            $chunk = (int)Request::get('chunkNumber', false);
            $chunks = (int)Request::get('totalChunks', false);

            $uniqueName = Request::get('identifier');

            // 移到临时文件夹,并以part1,part2后缀命名
            $this->moveFile($file, $uniqueName . '.part' . $chunk);

            $fullFilePath = $this->getTempPath() . '/' . $uniqueName;

            // 最后一个分片上传完成
            if ($chunk == $chunks) {
                // 把分片上传的文件拼起来
                for ($i = 1; $i <= $chunks; $i++) {
                    $partFilePath = $this->getTempPath() . '/' . $uniqueName . '.part' . $i;

                    // 有时文件已经生成,但是其他操作时报错,导致文件没有被移动,重传时,会把分片追加到之前的文件上去
                    // 所以先尝试删除
                    if ($i == 1) {
                        @unlink($fullFilePath);
                    }
                    $this->appendData(
                        $fullFilePath,
                        $partFilePath
                    );
                    @unlink($partFilePath);
                }

                $result = new UploadedFile($fullFilePath, $uniqueName);
            }
        }

        return $result;
    }

    /**
     * 返回存储分片文件和合成文件的临时目录
     *
     * @return string
     */
    protected function getTempPath()
    {
        $path = storage_path() . '/simple-upload';

        if (!is_dir($path)) {
            mkdir($path, 0777, true);
        }

        return $path;
    }

    /**
     * 把分片文件合成
     *
     * @param string $fullFilePath 合并后的文件名
     * @param string $partFilePath 分片文件名
     */
    protected function appendData($fullFilePath, $partFilePath)
    {
        if (!$out = @fopen($fullFilePath, 'ab')) {
            throw new \Exception("打开输出文件[$fullFilePath]出错");
        }

        if (!$in = @fopen($partFilePath, 'rb')) {
            throw new \Exception("打开输入文件[$partFilePath]出错");
        }
        while ($buff = fread($in, 4096)) {
            fwrite($out, $buff);
        }

        @fclose($out);
        @fclose($in);
    }

    /**
     * 存储分片文件到临时目录
     *
     * @param UploadedFile $file
     * @param string $fileName 分片文件名
     */
    protected function moveFile(UploadedFile $file, $fileName)
    {
        if (!file_exists($fileName)) {
            $file->move($this->getTempPath(), $fileName);
        }
    }

    /**
     * 返回是否是分片上传
     *
     * @return bool
     */
    protected function hasChunks()
    {
        return (bool)Request::get('totalChunks', false);
    }

    public function setPrefix($prefix)
    {
        $this->prefix = $prefix . '__';

        return $this;
    }
}